home *** CD-ROM | disk | FTP | other *** search
- Subject: v08i072: Bidirectional getty/login for SystemV, Part01/02
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: cdx39!jc@EDDIE.MIT.EDU (John Chambers)
- Mod.sources: Volume 8, Issue 72
- Archive-name: uutty/Part01
-
- [ I have not tried this. --r$ ]
-
- Hello. Enclosed is a program which I've been using for some
- time as a replacement for getty; I call it "uutty" as a hint
- that it cooperates with uucp/uux/mail/cu/etc. Several friends
- have suggested I broadcast it, so here it is....
-
- Uutty's primary function is to make it easy to use a port in
- both directions with little grief. On a port with an ACU-type
- modem, it allows both outgoing and incoming calls without any
- need to fiddle with inittab. On a direct link, it allows the
- use of commands like uucp or cu in either direction at any
- time.
-
- Uutty's secondary function is to try to recognize input from
- overly-intelligent modems or other login daemons, and avoid
- getting into a cycle-eating conversation with them.
-
- There is also a tertiary function: optionally producing an
- audit (debug) trail of traffic on the port at times when no
- program (such as uucico or cu) is using it. This is mostly
- useful when you have a talkative modem or LAN connection.
-
- This version should be classified as a "beta test" version;
- it has been tested on only a few varieties of Unix, and it
- will probably have to be modified for others. The two parts
- that may not be very portable are the code to put a port into
- raw mode (makeraw.c), and the code to log in a user (*.utmp.c).
-
- Another major reason for wanting the source code close at
- hand is that you will likely have to twiddle with the code
- that handles talkative modems, in order to respond correctly
- to your modems' own variety of bizarreness. An especially
- common problem is being overly sensitive to speed. Many
- modems won't accept commands at the full line speed (1200
- baud or whatever); they assume that commands come from a
- person typing at a keyboard, and lose characters when it
- comes from a program in a burst. This program writes the
- "init" strings byte-at-a-time, which may be slow enough,
- but you may have to slow these writes down even more to
- make the modem understand.
- : This is a shar archive. Extract with sh, not csh
- echo file: README
- cat > README << '\!Funky\!Stuff\!'
- The uutty package is John Chambers' very own person login
- daemon, to replace such things as getty(1) and login(1).
-
- There are several motives for doing this. You might have
- a modem which you wish to use for both incoming and outgoing
- calls. You might have a direct ("null modem") link which
- you would like to use from either end. You might have an
- overly-intelligent modem which is crashing your system by
- engaging getty in a conversation. All of these can be
- handled by uutty.
-
- Also, uutty will make an audit trail for you in the file
- of your choice. Note: at debug level -d2 and above,
- uutty is a "Trojan horse", since the audit trail will
- contain unencrypted login ids and passwords. This is
- very useful on occasion; it is also an extreme security
- risk. Think carefully before you try this on a regular
- basis.
-
- To create the program, first edit the *.h files and the
- Makefile. There isn't much that needs to be changed,
- but you probably want to modify the -DSYS5 and -DCadmus
- parameters to specify your variety of Unix and your
- manufacturer's name. You might also try:
- grep SYS5 *.c
- grep Cadmus *.c
- and check out all these pieces of code to see if they
- look correct for your system.
-
- If you make any interesting changes to port it to your
- system, you might share them with the author:
- ...!cdx39!jc (John Chambers)
- This will help towards producing a truly portable version
- of this logger.
-
- When you've convinced yourself that the system dependencies
- are OK, just type "make", and uutty will be compiled. To
- install it and the manual entry , type "install"; you'll
- have to be a super-user to do this.
-
- To run it, you need to explain to init about it. Here
- are some typical entries from our /etc/inittab file:
-
- t11:23 :respawn:modem /dev/tty11 -B12 # Modem for uucp.
- t30:234:respawn:uutty /dev/tty30 -B96 -e 2>>/user/aud/tty30 # Ordinary terminal port.
- t40:34:off : uutty /dev/tty40 -B96 2>>/user/aud/tty40 -l -d2 # Direct link.
- t41:34:respawn: uutty /dev/tty41 -B96 2>>/user/aud/tty41 -l -d2 # Direct link.
- t42:34:respawn: uutty /dev/tty42 -B96 2>>/user/aud/tty42 -l -d2 # Direct link.
- t43:34:respawn: uutty /dev/tty43 -B96 2>>/user/aud/tty43 -l -d2 # Direct link.
-
- What we are doing here is using uutty on four inter-machine
- direct links (null-modem or cross-over cables), on the
- tty4? ports. The tty30 port is attached to a terminal
- (well, actually to our LAN); uutty is being run there
- just to show that it works with the -e option. The tty11
- port is attached to an overly-intelligent ACU-type modem.
- The 'modem' program is a shell script, which looks like:
-
- > :
- > MODEM=tty11
- > /usr/lib/uucp/modem_init $1
- > cd /etc
- > PATH=.:$PATH
- > exec uutty /dev/$MODEM -B12 -L -d2 -i\\rqOG0\\rXXXT\\rqOG0 2>>/user/aud/$MODEM
- > :
- > : We normally won't reach this:
- > sleep 30
- > /usr/lib/uucp/modem_init $1
-
- The purpose of this is to run a special script, modem_init,
- to beat on the modem and try to put it into a quiescent state.
- When this is done, we run uutty at 1200 baud, with locking
- enabled, at debug level 2 (tracing of all input and output),
- and with a bizarre-looking initialization string which turns
- out to be what this particular modem requires to force it to
- hang up and re-initialize itself. The final sleep and call
- on modem_init are to handle cases where init somehow can't
- find uutty, or it dies instantaneously. This may look like
- overkill; it turns out to have been useful on occasion.
-
- Note that the audit trail grows without bound. Once a day,
- we handle it by having cron start up /etc/cleanup, a script
- that moves a select list of files to a backup copy. This
- generally suffices to keep the audit trail to a reasonable
- size.
-
- When you first run uutty, you should probably try it with
- -d5 or -d8, to have it explain what it's doing. It will
- likely get into a conversation with your modem; you'll
- have to figure out if there's a possible initialization
- string that will prevent it. Hint: Try to tell your
- modem not to echo anything.
-
- A more useful first test is to run uutty on one end of
- a null-modem cable, which could be to another computer,
- or to two ports on the same computer. Use cu(1) to
- connect to it, and have either getty or uutty running
- on the other end. After at most two RETURNs, you should
- get a login prompt, and uutty's audit trail should show
- that there is a lockfile. When you tell cu to disconnect,
- the lockfile will go away, and uutty will wake up in
- half a minute or so. If you are still logged in at
- the other end, uutty may discover this, and log you
- out; on the other hand, it may not. (It's supposed
- to, if you have a Unix prompt ending with '$' or '%'.)
-
- Enjoy!
-
- John M Chambers
- Phone: 617/364-2000x7304
- Email: ...{cthulhu,inmet,harvax,mit-eddie,mot[bos],rclex}!cdx39!{jc,news,root,usenet,uucp}
- Smail: Codex Corporation; Mailstop C1-30; 20 Cabot Blvd; Mansfield MA 02048-1193
- Telex: 922-443 CODEX A MNSF
- \!Funky\!Stuff\!
- echo file: Makefile
- cat > Makefile << '\!Funky\!Stuff\!'
- #
- # Makefile for uutty login daemon. To build uutty, just type:
- # make
- # To install uutty and the manual page, type:
- # make install
- # It's easiest to test if you create an inittab entry like:
- # t43:234:respawn:uutty /dev/tty43 -B96 -l -d8 2>>/user/aud/tty43
- # where /dev/tty43 is a null-modem link to a port on the same or
- # another Unix machine. It should be tested in two directions.
- # First, run it with no getty on the other end, and use cu from
- # the other end to call up uutty. After 1 or 2 CR or LF characters,
- # it should log you in. Next, start up getty or uutty on the other
- # end, and use cu to connect from this end. After CR or LF, uutty
- # should get out of the way and let the other end log you in.
- #
- CFL= -DSYS5 -DCadmus -I.
- CC= cc $(CFL) -c
- D= uutty.8
- H= *.h
- L= cc $(CFL) -o
- O= args.o awrite.o checkid.o copy.o data.o dbg.o die.o exec.o \
- fillutmp.o findutmp.o gestate.o getime.o help.o lastfield.o \
- lockname.o lockup.o lockwait.o main.o makeraw.o makesane.o \
- nextbyte.o opendev.o option.o pread.o pswd.o pwrite.o \
- restdev.o resync.o sendbrk.o shprompt.o sig.o slowly.o st.o \
- talk.o unlock.o
- S1= args.c awrite.c checkid.c copy.c data.c dbg.c die.c \
- exec.c fillutmp.c findutmp.c gestate.c getime.c help.c
- S2= lastfield.c lockname.c lockup.c lockwait.c \
- main.c makeraw.c makesane.c nextbyte.c opendev.c option.c pread.c \
- pswd.c pwrite.c restdev.c resync.c sendbrk.c shprompt.c \
- sig.c slowly.c st.c talk.c unlock.c
- S= $(S1) $(S2)
- U1= README Makefile install uutty.8 uutty.h dbg.h $(S1)
- U2= $(S2)
- #
- # How to compile most of the modules:
- #
- .c.o: $*.c $H; $(CC) $*.c
- #
- progs: uutty
- lints: uutty.L
- uutty: $O; $L uutty $O
- #
- # Libraries:
- #
- install: /etc/uutty /usr/man/man8/uutty.8
- /etc/uutty: uutty; Cp uutty /etc/uutty
- /usr/man/man8/uutty.8: uutty.8; Cp uutty.8 /usr/man/man8/uutty.8
- #
- # Some modules that need special treatment:
- #
- dbg.o: dbg.c dbg.h; $(CC) dbg.c
- makeraw.o: makeraw.c dbg.h; $(CC) makeraw.c
- makesane.o: makesane.c dbg.h; $(CC) makesane.c
- st.o: st.c; cc -c st.c
- #
- # Run lint on the whole mess:
- #
- uutty.L: $H $S; lint $(CFL) $S >uutty.L
- #
- # Build the distribution files:
- #
- uutty.dist: uutty.dist1 uutty.dist2
- uutty.dist1: uutty.cover1 uutty.shar1; cat uutty.cover1 uutty.shar1 >uutty.dist1
- uutty.dist2: uutty.cover2 uutty.shar2; cat uutty.cover2 uutty.shar2 >uutty.dist2
- #
- # Build the shell archives:
- #
- uutty.shar1: $(U1); shar $(U1) >uutty.shar1
- uutty.shar2: $(U2); shar $(U2) >uutty.shar2
- #
- \!Funky\!Stuff\!
- echo file: install
- cat > install << '\!Funky\!Stuff\!'
- : Script to install uutty.
- :
- echo You must be a super-user to do this...
- make install
- \!Funky\!Stuff\!
- echo file: uutty.8
- cat > uutty.8 << '\!Funky\!Stuff\!'
- .\" pltroff -manl $1
- .TH UUTTY 8
- .VE 5
- .SH NAME
- uutty \- two-ended login protocol with intelligent modem handling and uucp lockfiles
- .SH SYNOPSIS
- .B /etc/uutty
- device
- [
- .B \-b<speed>
- ] [
- .B \-d<level>
- ] [
- .B \-e
- ] [
- .B \-f
- ] [
- .B \-l
- ] [
- .B \-i
- initializer
- ] [
- 2>>audit_file
- ]
- .br
- file
- .SH DESCRIPTION
- .fi
- .B Uutty
- is a program that is invoked by
- .IR init (8).
- It is similar in function to getty(8) and login(1),
- but has some extra intelligence so that it may be run
- with a single modem used for both incoming and outgoing calls,
- or on both ends of a direct port-to-port link.
- .PP
- With
- .B uutty
- running on both ends of a line,
- terminal emulators like cu(1) may be used
- in either direction.
- Also, file transfer utilities like uucp(1)
- may be initiated from either end.
- .PP
- An important feature of
- .B uutty
- is that is recognizes the lockfiles created by uucico(8),
- cu(1), uux(1), and other programs.
- On most Unix(TM) systems,
- these are named "/usr/spool/uucp/LCK..<device>",
- where <device> is the last field of the device name.
- .B Uutty
- checks for the presence of such lockfiles before every read,
- and sleeps until they disappear.
- .PP
- Thus
- .B uutty
- may be left running on a port while other programs use it.
- When a lockfile is created by another program
- (such as uucico or cu),
- .B uutty
- will read at most one more chunk of input
- before noticing the lockfile.
- It will then "back off" until the other program
- signals that it is done with the device by
- unlinking the lockfile.
- .PP
- .B Uutty
- is normally run as a background daemon by init(1M).
- The entry in /etc/inittab typically looks like:
- .nf
- .in +5
- t42: 34:respawn: uutty /dev/tty42 -B96 -L 2>>somewhere
- .in -5
- .fi
- where
- .I somewhere
- is an audit file or /dev/null.
- .PP
- Initially
- .B uutty
- writes the initialization string, if one is given,
- then writes a "login:" prompt to the line.
- It then reads the response,
- and attempts to determine whether it is an
- acceptable login attempt,
- or whether it is from another login process
- (like itself or getty or login).
- In the former case, a password prompt is
- written to the device;
- in the latter case, the input is ignored.
- .PP
- An important difference between
- .B uutty
- and
- .B getty
- is that
- .B uutty
- echoes nothing back to the input device.
- This avoids uncontrolled feedback
- when programs are run on both ends of a line.
- However, with the
- .B \-e
- option, echoing is done.
- .PP
- .B Uutty
- does not invoke the
- .IR login (1)
- command;
- rather it does the entire login interview itself.
- .PP
- .I Device
- is the name of a serial port
- (normally in \f3/dev\fP) to which
- .B uutty
- is to attach itself.
- .B Uutty
- uses this string as the filename
- to open for reading and writing;
- it should be the full pathname of the device.
- .PP
- The optional argument,
- .B \-B
- .I <speed>,
- is a numeric line speed.
- Arbitrary speeds may not be recognized;
- typically -B300, -B1200, -B2400, -B4800, and -B9600
- are the only ones that work correctly.
- The default speed is -B9600.
- The final
- .I 00
- may be omitted.
- .PP
- .B Uutty
- sends a login prompt whenever it receives a single CR of LF character as input.
- It then expects a login id,
- which may be terminated by a new-line or carriage-return character.
- Either will cause
- .B uutty
- to examine the preceding characters for acceptability.
- The rules are:
- Only printable ASCII characters are accepted,
- and of those, most punctuation is rejected.
- In particular, any input containing a colon (:)
- is assumed to be a prompt from another login process,
- and causes
- .B uutty
- to become very uncommunicative.
- White space (blanks and tabs) are unacceptable,
- as are any ASCII control characters
- (those below hex 20).
- .PP
- Note that the initial CR or LF must be 'alone',
- ining that they must not be followed too soon by
- any other characters.
- If
- .B uutty
- finds junk in the input buffer after a CR or LF,
- the entire chunk of input is discarded.
- This is done to try to avoid getting into
- discussions with intelligent modems.
- .PP
- When acceptable input is received,
- a password prompt is sent,
- and the response (if any) is subjected to the same
- tests as for the login id.
- .PP
- If the login id and password agree with an entry in the
- password file /etc/passwd,
- the user's shell is initiated via execv(2),
- in the same process in which
- .B uutty
- was running.
- .PP
- If a ^C character (numeric 3) is received,
- .B uutty
- terminates.
- Also, this will usually result in the device not being open by any process,
- resulting in a "hangup" operation being performed by
- the device driver.
- See termio(8) for details.
- Normally, init(1M) will soon restart the process,
- and a new initialization string and login prompt will
- be sent to the device.
- .PP
- The
- .B \-i
- option is used to supply an initialization string
- to be sent when uutty determines that a connection
- exists to another system which should be terminated.
- The rest of the command-line argument should be the
- string, in which several types of notation may be
- used to produce non-printing characters.
- A complicated example is:
- .in +5
- .B "-i'\\\\33^T[j%7Fxx\\\\r'"
- .in -5
- The quotes are to prevent the shell from interpreting anything.
- The
- .B "\\\\33"
- is an octal value for an ASCII ESC character.
- The
- .B "^T"
- is a CTRL-T character, i.e., octal 24 or hex 14, ASCII DC4.
- The
- .B j
- represents itself.
- The
- .B "%7F"
- is a hex value for a DEL character.
- The
- .B xx
- represent themselves.
- The final
- .B "\\\\r"
- is a carriage-return character,
- as in the C language conventions.
- .PP
- A debug option is provided. When
- .B getty
- is invoked with the
- .B \-d<n>
- option, various debugging messages are produced,
- depending on the value of the digit <n>.
- Such messages are always written to the "standard error" file.
- The default is
- .B \-d1 ,
- which produces output giving the times at which
- .B uutty
- is started, and when it initiates a shell for some user.
- The
- .B \-d0
- level suppresses all output except fatal error messages.
- Higher numbers produce successively more output.
- The
- .B \-d4
- level will generally give sufficient information to
- explain just what messages are seen by
- .B uutty
- and why logins are succeeding or failing.
- .PP
- If user logins are desired on a port used by uucp(1),
- it is a good idea to create lockfiles.
- Otherwise, a uucp demon (uucico) may attempt to use the port,
- and sheer insanity results.
- The
- .B \-l
- option causes a uucp lockfile to be created for the duration of a login,
- preventing uucp from attempting to use the port.
- On logout, the lockfile will be removed.
- Note:
- This implies that the shell is run as a subprocess to uutty,
- so ps(1) will show both processes running.
- Don't kill the uutty process;
- doing so will block further accesses to the port by
- uutty or uucp,
- until you delete the lockfile by hand.
- .PP
- If for some reason you wish to start shells in subprocesses,
- this may be done via the
- .B \-f
- option, which stands for "fork".
- The
- .B \-l
- option implies the
- .B \-f
- option.
- .SH FILES
- /etc/passwd
- /etc/utmp
- /usr/spool/uucp/LCK..<device> .
- Note: /etc/gettydefs is not referenced by
- .I uutty .
- .SH "SEE ALSO"
- cu(1),
- getty(8),
- init(8),
- inittab(5),
- ioctl(2),
- login(1),
- tty(7),
- uucico(8),
- uucp(1),
- uux(1)
- .SH "BUGS"
- Programs that don't know how to create uucp(1) lockfiles shouldn't
- be run on a port controlled by
- .B uutty .
- If you must, try surrounding them with a script that creates the
- lockfile.
- .PP
- The
- .B \-e
- option entails a high risk of feedback saturating either or both
- of the computers involved.
- .PP
- If a
- .B CR
- or
- .B LF
- is followed too quickly by further input,
- it will be silently discarded.
- This is frustrating to people that like to bang
- on the RETURN key.
- .PP
- There are all sorts of truly demented modems on the market;
- you may well have to twiddle with the code a bit to persuade
- .B uutty
- to ingore your modem's noise.
- .PP
- At debug levels -d2 and above,
- .B uutty
- is a Trojan Horse,
- writing login ids and passwords in the clear to the audit trail.
- \!Funky\!Stuff\!
- echo file: uutty.h
- cat > uutty.h << '\!Funky\!Stuff\!'
- #ifndef uutty_h
- #include "dbg.h"
- /*
- ** This is the header file for John Chambers' "Serial Port Daemon".
- ** Several programs use this header, including "uutty", so there
- ** is likely to be stuff here not needed by a particular program.
- ** A single header is used to make them somewhat consistent.
- */
- /*
- ** The following stuff may be specific to Unix SYS/V:
- */
- #ifdef SYS5
- #include <pwd.h>
- #include <termio.h>
- #include <utmp.h>
- #include <sys/errno.h>
- #include <sys/stat.h>
- extern struct passwd*getpwnam();
- extern int ttyslot();
- extern struct utmp *getutent();
- extern struct utmp *getutline();
- extern void pututline();
- extern void setutent();
- extern struct stat status; /* Child process's status */
- extern struct termio trminit;
- extern int ttyslot();
- extern struct utmp *up;
- extern struct utmp utmp;
- #endif
- /*
- ** Unix library stuff:
- */
- extern char **environ; /* Environment vector */
- extern char *crypt(); /* Password encryption */
- extern char *ctime(); /* Date/time in ASCII */
- /*
- ** State-type codes, see also the state[] array.
- */
- #define S_INIT 0
- #define S_IDLE 1
- #define S_LOGIN 2
- #define S_PASSWD 3
- #define S_DL 11
- #define S_RX 12
- #define S_TC 13
- #define S_BV_E 14
- #define S_HSUQ 15
- #define S_HSU 16
- #define S_READS 17
- #define S_GO 18
- #define S_TRANS 19
- #define S_CTRLA 20
- #define S_CTRLB 21
- #define S_CTRLC 22
- #define S_CTRLD 22
- #define S_CONNECT 33
- #define S_ID 34
- #define S_SREC 36
- #define S_SR 37
- #define S_EXIT 38
- #define S_LOAD 39
- /*
- ** Array sizes.
- */
- #define BUF 80 /* Size of scratch buffer */
- #define IBUF 1000 /* Size of input buffer */
- #define OBUF 80 /* Size of output buffer */
- #define RSP 1000 /* Size of response buffer */
- #define SREC 80 /* Size of S-record buffer */
- /*
- ** Assorted pseudo-functions.
- */
- #define ASCII(c) ((c)&0x7F)
- #define Awrite(m) awrite(m)
- #define CTRL(c) ((c)&0x1F)
- #define Dmp(a,s) dmp((long)(a),(long)(s))
- #define Pread(c,p,s) pread((int)(c),(char*)(p),(int)(s))
- #define Pwrite(p) pwrite((char*)(p))
- #define Resync resync()
- #define Slowly if (slowfl) slowly()
- /*
- ** These might be in some standard libraries:
- */
- #define islower(c) ('a'<=(c)&&(c)<='z')
- #define isupper(c) ('A'<=(c)&&(c)<='Z')
- #define htob(c) ((('0'<=c)&&(c<='9'))?(c-'0'):\
- (('A'<=c)&&(c<='F'))?(c-'A'+10):\
- (('a'<=c)&&(c<='f'))?(c-'a'+10):-1)
- /*
- ** Limit type codes:
- */
- #define L_READS 10
- #define L_ES 2
- #define L_TC 3
- #define L_DL 4
- #define L_LOAD 4
- #define L_RX 5
- #define L_START 6
- #define L_TRIES 10
- /*
- ** Misc constants:
- */
- #define READS 3 /* Read attempts before failure */
- #define NUDGES 5 /* Nudge attempts before failure */
- #define EGARBAGE 101
- #define ETIMEOUT 102
- #define THRESH 3 /* Number of failures that elicits prompt */
- /*
- ** Sleep times for various routines.
- */
- #define SLEEP1 1
- #define SLEEP2 1
- #define SLEEP3 1
- #define SLEEPR 1
- #define SLEEPF 10
- #define SLEEPL 10
- /*
- ** Pseudo-commands.
- */
- #define Dead goto dead
- #define Response goto response
- #define Nudge goto nudge
- /*
- ** Pseudo-types.
- */
- #define uint unsigned int
- /*
- ** Assorted messages.
- */
- extern char m_CTRLA [];
- extern char*m_exit;
- extern char m_login [];
- extern char m_passwd[];
- extern char*m_init;
- extern char*m_init1;
- extern char*m_init2;
- extern char*m_init3;
- extern char*m_nudge;
- /*
- ** Assorted global function typess.
- */
- extern char * ctime();
- extern char * gestate();
- extern char * getime();
- extern char * lastfield();
- extern struct utmp * findutmp();
- /*
- ** Assorted global variables.
- */
- extern uint count; /* Delay between "typed" chars */
- extern char *ctime(); /* Time in ASCII format */
- extern long currtime; /* Timestamp */
- extern char *ctimep; /* Current ctime() value */
- extern char *device; /* Name of serial port */
- extern int dev; /* Number of serial port file */
- extern char *devfld; /* Last field of device name */
- extern Flag echofl; /* True if input is to be echoed */
- extern Flag echoing; /* True if input is being echoed */
- extern int eol0; /* Alternate EOL character */
- extern int exitstat; /* Status to report to exit() */
- extern int files; /* Number of files processed */
- extern Flag forkfl;
- extern char ibuf[IBUF]; /* Buffer for input from port */
- extern char *ibfa; /* First valid char of ibuf */
- extern char *ibfz; /* Last+1 valid char of ibuf */
- extern int iomask; /* Constant to convert values to ASCII */
- extern int l_tries; /* Number of reads between nudges */
- extern int l_reads; /* Number of reads before timeout */
- extern Flag locked; /* True if lockfile exists*/
- extern Flag lockfl; /* Create lockfile on login */
- extern int lockfn; /* Lockfile number */
- extern char lockfile[50]; /* Place to build lockfile name */
- extern char lockroot[]; /* Pathname for creating lockfiles */
- extern int nudges; /* Number of times we've nudged */
- extern int Nudges; /* Limit to nudge attempts */
- extern int lsleep; /* Sleep time for locks */
- extern char *oldtarg; /* Previous name of target */
- extern char *path; /* Default search path */
- extern Flag pathfl;
- extern int pid; /* Our process id number */
- extern char *prgnam; /* Last field of program's name */
- extern Flag raw; /* True if I/O is to be raw */
- extern char rsp[1+RSP]; /* Response buffer */
- extern uint rspmax; /* Max response we can handle */
- extern uint rspsiz; /* Current size of response buffer */
- extern Flag slow; /* True if output should be slow */
- extern Flag slowfl; /* True if count or slow turned on */
- extern int ss; /* State: code for last action */
- extern char *target; /* Name of thing on other side of port */
- extern Flag termfl; /* True if terminal state changed */
- extern struct termio trminit; /* Initial ioctl() setting for device */
- extern uint timeout; /* Global timeout interval */
- /*
- ** User identification stuff:
- */
- #define PASSWD 16 /* Max length of a passwd */
- #define USERID 16 /* Max length of a userid */
- extern char passwd[1+PASSWD]; /* Current passwd */
- extern char userid[1+USERID]; /* Current userid */
- extern int euid; /* Effective user id number */
- extern int ruid; /* Real user id number */
- extern int egid; /* Effective group id number */
- extern int rgid; /* Real group id number */
- /*
- ** Definitions of non-int-valued functions:
- */
- struct utmp *findutmp();
- struct utmp *findutmp();
- char *getime();
- char *lastfield();
- /*
- ** Some common gotos:
- */
- #define Done goto done
- #define Fail goto fail
- #define Loop goto loop
-
- #ifdef SYS5
- #endif
-
- #define uutty_h
- #endif
- \!Funky\!Stuff\!
- echo file: dbg.h
- cat > dbg.h << '\!Funky\!Stuff\!'
- #ifndef dbg_h
- #include <stdio.h>
- #include <sys/types.h>
- /*
- ** The global 'debug' variable controls the level of diagnostics
- ** to be produced. Some suggested conventions are:
- ** debug=0 fatal error messages only.
- ** debug=1 diagnostic: serious messages and warnings, default.
- ** debug=2 informative: major events and decisions.
- ** debug=3 gabby: tracing of likely trouble spots.
- ** debug=4 tracing of important events for troubleshooting.
- ** debug=5 major function calls and returns.
- ** debug=6 details of flow of control.
- ** debug=7 major data tracing.
- ** debug=8 detailed data tracing.
- ** debug=9 everything of conceivable interest to anyone.
- ** Of course, it is entirely up to you how you use the debug
- ** level, and many applications won't have a need for 10 levels.
- ** It will help others trying to use your code if they can use
- ** the debug level easily to find out what's wrong. At level
- ** 1, in particular, it is a good idea to give enough info to
- ** tell the user what went wrong. For instance, don't just say
- ** that you can't write to a file; show the pathname that you
- ** failed to open for writing, and the errno code (even better,
- ** give the sys_errlist[errno] message).
- */
- typedef char Flag;
- typedef unsigned char U8;
- typedef unsigned short U16;
- typedef unsigned long U32;
- /*
- ** Main debug-message pseudo-functions:
- */
- #define D if(debug> 1)dmsg
- #define D1 if(debug>=1)dmsg
- #define D2 if(debug>=2)dmsg
- #define D3 if(debug>=3)dmsg
- #define D4 if(debug>=4)dmsg
- #define D5 if(debug>=5)dmsg
- #define D6 if(debug>=6)dmsg
- #define D7 if(debug>=7)dmsg
- #define D8 if(debug>=8)dmsg
- #define D9 if(debug>=9)dmsg
- #define E emsg
- #define P pmsg
- #define V if(debug>0)pmsg
- #define W wmsg
- /*
- ** These functions produce a 1-line dump, with non-printable
- ** characters converted to 2-char escape sequences.
- */
- #define Ascdump(a,n,o,m) ascdump((char*)(a),(U32)(n),(U32)(o),(char*)(m))
- #define Ascdp(a,p) Ascdump(a,p-a+1,a,0)
- #define Ascdn(a,n) Ascdump(a,n,a,0)
- #define Ascdpm(a,p,m) Ascdump(a,p-a+1,0,m)
- #define Ascdnm(a,n,m) Ascdump(a,n,0,m)
- /*
- ** These functions produce a 3-line dump, consisting of displayable
- ** characters, high-order hex digit, and low-order hex digit. On
- ** the first line, non-printing characters are shown as '_'.
- */
- #define Hexdump(a,n,o,m) hexdump((char*)(a),(U32)(n),(U32)(o),(char*)(m))
- #define Hexdp(a,p) Hexdump(a,p-a+1,a,0)
- #define Hexdn(a,n) Hexdump(a,n,a,0)
- #define Hexdpm(a,p,m) Hexdump(a,p-a+1,0,m)
- #define Hexdnm(a,n,m) Hexdump(a,n,0L,m)
-
- extern int ascdump(); /* The actual ASCII-dump routine */
- extern char *crlf; /* Line terminator string, usually "\n" */
- extern int debug; /* Debug level, 0-9, default=1 */
- extern int dbgsleep; /* Sleep time after output, default=0 */
- extern FILE *dbgout; /* Diagnostic output stream, default=stderr */
- extern int dsp(); /* Convert an int to a printable char */
- extern char *dbgtimep; /* Time to display in debug messages */
- extern int errno; /* Unix global error code */
- extern int hexdump(); /* The actual hex-dump routine */
- extern char *progname; /* Name of running program, from argv[0] */
-
- #define dbg_h
- #endif
- \!Funky\!Stuff\!
- echo file: args.c
- cat > args.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Process the command-line arguments.
- */
- args(ac,av)
- char **av;
- { int a;
-
- for (a=1; a<ac; a++) {
- D3("arg %d=\"%s\"",a,av[a]);
- switch (av[a][0]) {
- case '-':
- case '+':
- D6("opt %d=\"%s\"",a,av[a]);
- option(av[a]);
- continue;
- default:
- switch(files++) {
- case 0: /* Name of serial port */
- device = av[a];
- break;
- default:
- E("Too many args; \"%s\" ignored.",av[a]);
- }
- }
- }
- }
- \!Funky\!Stuff\!
- echo file: awrite.c
- cat > awrite.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Write a character string to the port, stopping at the first null,
- ** and processing a variety of escape sequences. This routine always
- ** writes one byte at a time. Doing a system call per byte is a bit
- ** wasteful of processor time, but it helps assure that we won't flood
- ** the poor little helpless modem.
- */
- #define Gotbyte goto gotbyte
-
- awrite(msg)
- char*msg;
- { int i, n;
- char c, d, *p;
-
- D5("awrite(%08lX)",msg);
- if (debug) {
- dbgtimep = getime();
- if (debug >= 2) P("%s Send: %s",dbgtimep,msg);
- if (debug >= 4) Hexdnm(msg,1,"Send:");
- }
- n = strlen(msg);
- D8("port_wr:slow=%d",slow);
- p = msg;
- while (c = *p++) {
- switch (c) {
- case '^': /* CTRL-X notation */
- c = *p++ & 0x3F;
- Gotbyte;
- case '%': /* %AB is a hex value */
- c = 0;
- n = 2; /* Accept at most 2 digits */
- while (n-- > 0) {
- switch (d = *p) {
- case '9': case '8': case '7': case '6': case '5':
- case '4': case '3': case '2': case '1': case '0':
- c = (c << 4) | (c - '0');
- Gotbyte;
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- c = (c << 4) | (c - 'A' + 10);
- Gotbyte;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- c = (c << 4) | (c - 'a' + 10);
- Gotbyte;
- default:
- goto gotbyte;
- }
- ++p;
- }
- Gotbyte;
- case '\\': /* Escape notation */
- switch (c = *p++) {
- case '7': case '6': case '5': case '4':
- case '3': case '2': case '1': case '0':
- c -= '0';
- if ((d = *p) && ('0'<=d && d<='7')) {
- c = (c << 3) | (d - '0');
- ++p;
- if ((d = *p) && ('0'<=d && d<='7')) {
- c = (c << 3) | (d - '0');
- ++p;
- }
- }
- Gotbyte;
- case 'B': case 'b': c = '\b'; Gotbyte;
- case 'D': case 'd': sleep(1); continue;
- case 'N': case 'n': c = '\n'; Gotbyte;
- case 'R': case 'r': c = '\r'; Gotbyte;
- case 'T': case 't': c = '\t'; Gotbyte;
- case 'X': case 'x': sendbrk(dev); continue;
- default : c = d; Gotbyte;
- }
- }
- gotbyte: Slowly;
- if (debug >= 3) {
- dbgtimep = getime();
- if (debug >= 3) Ascdnm(&c,1,"Write:");
- if (debug >= 4) Hexdnm(&c,1,"Write:");
- }
- D4("awrite: c=%02X='%c'",c,dsp(c));
- D9("port_wr:before write(%d,%06lX,%d)",dev,&c,1);
- i = write(dev,&c,1);
- D9("port_wr: after write(%d,%06lX,%d)=%d",dev,&c,1,i);
- if (i <= 0) {
- if (debug) P("%s: write failed, quitting.",getime());
- die(2);
- }
- }
- }
- \!Funky\!Stuff\!
- echo file: checkid.c
- cat > checkid.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** The response string is believed to contain a login id.
- ** The id is copied to the global variable "userid", and
- ** its length returned.
- */
- checkid(rp)
- char *rp;
- { char *p, *q;
-
- D4("checkid: r=\"%s\" ss=%d",rp,ss);
- for (p=rp; *p; ++p) { /* Examine the chars for acceptability */
- switch(*p) {
- case 0x04: /* EOT triggers a login prompt */
- Pwrite("login:");
- target = "?";
- ss = S_LOGIN;
- D4("State %d=%s",ss,gestate());
- return 1;
- case ' ': /* Blanks aren't legal */
- case ':': /* Colons aren't legal */
- case '\b': /* Backspaces aren't legal */
- case '\t': /* Tabs aren't legal */
- D3("ID with whitespace ignored.");
- ss = S_IDLE;
- D4("State %d=%s",ss,gestate());
- Fail;
- case '\0': /* Assorted terminal chars */
- case '\r':
- case '\n':
- *p = 0;
- goto good;
- case '!': /* Special goodie for killing daemon */
- if (p[1] == 'Q') {
- E("!Q in input; ");
- if (debug) P("%s: !Q in input, quitting [id]",getime());
- die(0);
- }
- default:
- continue;
- }
- }
- good: /* Make a copy of the supposed id */
- p = rp;
- q = userid;
- while (*p && q<userid+USERID)
- *q++ = *p++;
- *q = 0;
- if (debug >= 2) P("%s USERID=\"%s\"",getime(),userid);
- target = "logger";
- return (p-rp);
- fail: return 0;
- }
- \!Funky\!Stuff\!
- echo file: copy.c
- cat > copy.c << '\!Funky\!Stuff\!'
- /* Copy *s to *t, n bytes.
- */
- copy(t,s,n)
- char *t, *s;
- int n;
- {
- while (n-- > 0)
- *t++ = *s++;
- }
- \!Funky\!Stuff\!
- echo file: data.c
- cat > data.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- #include <signal.h>
-
- /*
- ** Assorted messages.
- */
- char*m_exit = 0; /* May be set to special exit message */
- char m_login [] = "\r\nlogin:"; /* Unix login prompt */
- char m_passwd[] = "\r\npassword:"; /* Unix password prompt */
- char*m_init = 0; /* Special init string for device */
- char*m_init1 = 0; /* May be set to special init message */
- char*m_init2 = "\r"; /* Normal nudge to get first response */
- char*m_init3 = 0; /* May be set to special init message */
- char*m_nudge = "\r"; /* What to send to trigger a response */
- /*
- ** Assorted global variables.
- */
- int baudmask = 0; /* CBAUD mask for termio ioctl (B1200, B9600, etc) */
- int baudrate = 0; /* Numeric value of baud rate (1200, 9600, etc) */
- uint count = 0; /* Delay between "typed" chars */
- long currtime; /* Timestamp */
- char *ctimep = "?"; /* ASCII form of currtime */
- char *device = 0; /* Name of serial port */
- int dev = 0; /* Number of serial port */
- char *devfld= "?"; /* Last field of device name */
- Flag echofl = 0; /* True if input is to be echoed */
- Flag echoing= 0; /* True if input is being echoed */
- int eol0 = -1; /* Extra EOL char to recognize */
- int exitstat = 0;
- int files = 0;
- char ibuf[IBUF]; /* Buffer for input from port */
- char *ibfa = ibuf; /* First valid char of ibuf */
- char *ibfz = ibuf; /* Last+1 valid char of ibuf */
- int iomask = 0x7F; /* Converts chars to ASCII */
- int l_tries= L_TRIES; /* Number of reads between nudges */
- int l_reads= L_READS; /* Number of reads before timeout */
- int lsleep = 30; /* Sleep time when we hit a lockfile */
- Flag locked = 0; /* Lockfile created */
- Flag lockfl = 0; /* Create lockfile on login */
- int lockfn = -1; /* Lockfile number */
- char lockfile[50] = {0}; /* Place to build lockfile name */
- char lockroot[] = "/usr/spool/uucp/LCK..";
- int nudges = 0; /* Number of times we've nudged */
- int Nudges = NUDGES; /* Limit to nudge attempts */
- char *oldtarg = "?"; /* Previous name for thing on other side of port */
- int pid = -1; /* Our process id number */
- char *prgnam = "?"; /* Last field of program's name */
- Flag raw = 1; /* Raw I/O on device? */
- char rsp[1+RSP]; /* Response buffer */
- uint rspmax = RSP; /* Max response we can handle */
- Flag slow = 0;
- Flag slowfl = 0; /* True if count or slow turned on */
- int ss = S_INIT; /* State: code for last action */
- char *target = "port"; /* Name of thing on other side of port */
- Flag termfl = 0; /* True if terminal state changed */
- /*
- ** User identification stuff:
- */
- char passwd[1+PASSWD] = {0}; /* Current passwd */
- char userid[1+USERID] = {0}; /* Current userid */
- int euid = -1; /* Effective user id number */
- int ruid = -1; /* Real user id number */
- int egid = -1; /* Effective group id number */
- int rgid = -1; /* Real group id number */
-
- #ifdef SYS5
- struct stat status; /* Child process's status */
- struct termio trminit = {0}; /* For saving terminal (ioctl) status */
- struct utmp *up = 0; /* Pointer to /etc/utmp entry */
- struct utmp utmp = {0}; /* Scratch /etc/utmp entry */
- #endif
-
- \!Funky\!Stuff\!
- echo file: dbg.c
- cat > dbg.c << '\!Funky\!Stuff\!'
- /* John Chambers' debugging package for C programs. This
- ** package is intended, among other things, to be added to
- ** other peoples' software after the fact to aid in getting
- ** it to run. An attempt has been made to avoid global
- ** names that others will use, though there are likely
- ** to be collisions with other debugging packages. The
- ** most common source of conflicts is due to the fact that
- ** this package includes <stdio.h> and <sys/types.h>; you
- ** should hunt down references to either of these and put
- ** the line:
- ** #include <dbg.h>
- ** in place of both of them.
- **
- ** The primary functions defined here are based on conditional
- ** calls of printf(), with the program's name inserted at the
- ** start, a newline appended, and fflush() called to send it
- ** on its way. There is also a hexdump() routine to produce
- ** a hex dump of a chunk of memory, and an ascdump() routine
- ** to display things in ASCII form. All these are intended
- ** to be called via the macros defined in "dbg.h".
- **
- ** The global variable "debug" should be set to a value in [0,9],
- ** to control the amount of debugging output.
- **
- ** Note that "dbgout" is a FILE*, either stdout or stderr as you
- ** wish, with stderr the default.
- */
- #include "dbg.h"
-
- static char dbgheader[] = "@(#)RELEASE: 1.0 Sep 20 1986 ~jc/dbg";
- /*
- ** If you normally use terminals with a particular line
- ** length, you might adjust these. Note that there is
- ** an initial 7-byte fieldin all lines, plus a newline,
- ** so MAXCOLS should be >= MAXCHS+8.
- */
- #define MAXCOLS 80 /* Max length of print line */
- #define MAXCHRS 64 /* Max chars in one hexdump chunk */
-
- extern int errno; /* Unix error code */
- char *crlf = "\n"; /* Line terminator string, might be "\n\r" */
- FILE *dbgout = stderr; /* Can be assigned to switch to stdout */
- int dbgsleep = 0; /* Sleep time (secs) after messages */
- int debug = 1; /* Set to desired debug level (0-9) */
- char *dbgtimep = 0; /* Set to ASCII date/time if desired in output */
- static int hex_chrs = MAXCHRS; /* Number of chars to dump in one line */
- static int hex_cols = MAXCOLS; /* Length of print line */
- static int hex_word = MAXCHRS; /* Number of bytes to group together */
- char *progname = "?"; /* Set to argv[0] */
- /*
- ** Debug output routine. The program's name is
- ** prepended to the message, a terminator is added,
- ** and an optional sleep is done.
- */
- /*VARARGS1*//*ARGSUSED*/
- dmsg(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) char *fmt;
- { int n;
- n = fprintf(dbgout,"%s: ",progname);
- n += fprintf(dbgout,fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
- n += fprintf(dbgout,crlf);
- fflush(dbgout);
- if (dbgsleep) sleep(dbgsleep);
- return n;
- }
- /* Note that emsg() writes to both dbgout and stderr.
- */
- /*VARARGS1*//*ARGSUSED*/
- emsg(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) char *fmt;
- { int n;
- if (dbgout != stderr)
- n = dmsg(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
- n += fprintf(stderr,"%s: ",progname);
- n += fprintf(stderr,fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
- n += fprintf(stderr,crlf);
- fflush(stderr);
- return n;
- }
- /* Print a message to the debug output, adding only
- ** a terminator, but don't add program identification.
- */
- /*VARARGS1*//*ARGSUSED*/
- pmsg(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) char *fmt;
- { int n;
- n = fprintf(dbgout,fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
- n += fprintf(dbgout,crlf);
- fflush(dbgout);
- if (dbgsleep) sleep(dbgsleep);
- return n;
- }
- /* Write a message to the debug output, adding nothing.
- */
- /*VARARGS1*//*ARGSUSED*/
- wmsg(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) char *fmt;
- { int n;
- n = fprintf(dbgout,fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
- fflush(dbgout);
- if (dbgsleep) sleep(dbgsleep);
- return n;
- }
- /*
- ** Hexdump routine. The params are a starting address,
- ** a byte count, an address to show on the output (which
- ** is often the starting address), and an optional message
- ** for labeling the dump. If the message is present, the
- ** address is not displayed, since they both would appear
- ** at the same place in the output.
- **
- ** Note that the actual output is done by pmsg().
- */
- static char hex_cc[1+MAXCOLS];
- static char hex_hi[1+MAXCOLS];
- static char hex_lo[1+MAXCOLS];
- static int ascfl = 0; /* True if hex dump not wanted */
- /*
- ** Produce only the ASCII line; omit the two hex lines.
- */
- ascdump(a,n,o,m)
- char *a; /* Address of first byte to dump */
- U32 n; /* Number of bytes */
- char *o; /* Offset (address) to report */
- char *m; /* Initial message, if o==NUL */
- { int c;
-
- D4("ascdump(a=%06lX,n=%d,o=%06lX,m=%06lX)",a,n,o,m);
- if (dbgtimep) fprintf(dbgout,"%s ",dbgtimep);
- if (m) sprintf(hex_cc,"%s ",m);
- else sprintf(hex_cc,"%7d ",o);
- fprintf(dbgout,"%7.7s",hex_cc);
- fflush(dbgout);
- while (n-- > 0) {
- c = *a++ & 0x7F;
- switch (c) {
- case '\0': fprintf(dbgout,"\\0"); break;
- case '^' : fprintf(dbgout,"\\^"); break;
- case '\\': fprintf(dbgout,"\\\\"); break;
- case '\b': fprintf(dbgout,"\\b"); break;
- case '\n': fprintf(dbgout,"\\n"); break;
- case '\r': fprintf(dbgout,"\\r"); break;
- case '\t': fprintf(dbgout,"\\t"); break;
- case 0x7F: fprintf(dbgout,"\\D"); break;
- default:
- if (c < ' ') {
- fprintf(dbgout,"^%c",c|0x40);
- break;
- }
- fprintf(dbgout,"%c",c);
- break;
- }
- }
- fprintf(dbgout,crlf);
- fflush(dbgout);
- }
- /*
- */
- hexdump(a,n,o,m)
- char *a; /* Address of first byte to dump */
- U32 n; /* Number of bytes */
- U32 o; /* Offset (address) to report */
- char *m; /* Initial message, if o==NUL; -1 for ascii only */
- {
- ascfl = 0;
- return hex_dump(a,n,o,m);
- }
- /*
- */
- hex_dump(a,n,o,m)
- char *a; /* Address of first byte to dump */
- U32 n; /* Number of bytes */
- U32 o; /* Offset (address) to report */
- char *m; /* Initial message, if o==NUL; -1 for ascii only */
- { int col, i;
- char c;
-
- hex_init(m,o);
- col = 0;
- while (n) {
- c = *a++;
- i = 7 + col + (col / hex_word);
- n--;
- hex_lo[i] = hex_dig(c & 0xF);
- hex_hi[i] = hex_dig((c >> 4) & 0xF);
- hex_cc[i] = dsp(c);
- col++;
- o++;
- if (col >= hex_chrs) {
- hex_out();
- hex_init(m,o);
- col = 0;
- }
- }
- if (col > 0) hex_out();
- return 0;
- }
- /* Generate a printable char for x. If x is an ASCII
- ** printable char, it is returned. For others, '_' is
- ** returned.
- */
- dsp(x)
- { x &= 0x7F;
- return (0x20<=x && x<=0x7E) ? x : '_';
- }
- /* Given a small integer [0-15], this routine returns
- ** the corresponding ASCII char for a hex digit.
- */
- hex_dig(x)
- { return ( 0<=x && x<= 9) ? '0' + x
- : (10<=x && x<=15) ? 'A' + x - 10
- : '_';
- }
- /* Initialize the line images for a given address.
- */
- hex_init(m,a)
- char *m; /* Initial message (<=8 chars) */
- U32 a; /* Address reported on output */
- { int i;
-
- i = hex_chrs + (hex_chrs / hex_word) + 8; /* Length of print line (including final newline) */
- if (hex_cols < i) {
- hex_cols = i;
- D5("hex_init: cols=%d chrs=%d word=%d",hex_cols,hex_chrs,hex_word);
- }
- for (i=0; i<=hex_cols; i++)
- hex_cc[i] = hex_hi[i] = hex_lo[i] = ' ';
- if (m && a==0) {
- strcpy(hex_cc,m);
- } else {
- sprintf(hex_cc,"%6ld: ",a);
- sprintf(hex_hi,"%6lX: ",a);
- }
- return 0;
- }
- /* The three lines of hex dump info are complete;
- ** do a bit of straightening out, and print them.
- */
- hex_out()
- { int i;
-
- for (i=0; i<=hex_cols; i++) { /* sprintf() may produce nulls */
- if (hex_cc[i] == 0) hex_cc[i] = ' ';
- if (hex_hi[i] == 0) hex_hi[i] = ' ';
- if (hex_lo[i] == 0) hex_lo[i] = ' ';
- }
- for (i=hex_cols; i>0; i--) /* Trim lines */
- if (hex_cc[i] == ' ')
- hex_cc[i] = 0;
- else break;
- for (i=hex_cols; i>0; i--)
- if (hex_hi[i] == ' ')
- hex_hi[i] = 0;
- else break;
- for (i=hex_cols; i>0; i--)
- if (hex_lo[i] == ' ')
- hex_lo[i] = 0;
- else break;
- if (dbgtimep) fprintf(dbgout,"%s ",dbgtimep);
- pmsg("%s",hex_cc); /* Symbolic dump */
- if (ascfl == 0) {
- if (dbgtimep) fprintf(dbgout,"%s ",dbgtimep);
- pmsg("%s",hex_hi); /* High-order hex digit */
- if (dbgtimep) fprintf(dbgout,"%s ",dbgtimep);
- pmsg("%s",hex_lo); /* Low-order hex digit */
- }
- if (dbgsleep) sleep(dbgsleep);
- return 0;
- }
- \!Funky\!Stuff\!
- echo file: die.c
- cat > die.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- #include <signal.h>
-
- die(retval)
- { int i;
-
- D4("die(%d)",retval);
- if (locked) unlock();
- l_tries = l_reads = 1; /* Give up quickly */
- Resync; /* Gobble up all input */
- if (m_exit) Awrite(m_exit); /* Special exitial message? */
- if (termfl && isatty(dev)) { /* Restore terminal status */
- D7("die: %d:\tcflag=%06o",dev,trminit.c_cflag);
- D7("die: %d:\tiflag=%06o",dev,trminit.c_iflag);
- D7("die: %d:\tlflag=%06o",dev,trminit.c_lflag);
- D7("die: %d:\toflag=%06o",dev,trminit.c_oflag);
- D5("die:before ioctl(%d,%d,%06lX)",dev,TCSETA,&trminit);
- i = ioctl(dev,TCSETA,&trminit);
- D5("die: after ioctl(%d,%d,%06lX)=%d",dev,TCSETA,&trminit,i);
- D3("File %d restored to normal.",dev);
- }
- exit(retval);
- }
- \!Funky\!Stuff\!
- echo file: exec.c
- cat > exec.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Start up a new program in the current process. This is normally
- ** to start up a shell for a logged-in user. If the command can't
- ** be executed, -1 is returned. Note that we can define a new search
- ** path here which will overwrite the one we were given.
- */
- Flag forkfl = 0; /* Should we fork or exec directly? */
- Flag pathfl = 0; /* True if PATH defined in environment */
- /*
- ** The 'path' variable should be defined appropriately for your
- ** system. If it is null, we will just pass on the path that
- ** was handed to us, which may be right on many systems.
- */
- #ifdef Cadmus
- char *path = "PATH=:.:/bin:/bin.cadmus:/bin.sys5:/bin.sys3:/bin.ver7:/usr/ucb:/usr/bin:/etc:/usr/local:/usr/new:";
- #define Path
- #endif
- #ifdef VME
- char *path = "PATH=:.:/bin:/usr/bin:/etc:";
- #define Path
- #endif
- #ifndef Path
- char *path = 0; /* No search path */
- #endif
-
- exec(cook,cmd,pp)
- int cook; /* Should we do cooked or raw I/O? */
- char *cmd; /* Null-terminated command */
- struct passwd *pp; /* The user's /etc/passwd entry, unpacked */
- { int a, c, e, i, n, r;
- int child;
- Flag lognfl, shelfl, homefl;
- char *av[10]; /* This should be room enough */
- char *cp, *dp;
- char**ev;
- char arg0[30]; /* For shell's visible name */
- char logn[30]; /* For LOGNAME=<id> string */
- char home[30]; /* For HOME=<dir> string */
- char shll[30]; /* For SHELL=<prog> string */
- char *shell="/bin/sh"; /* default shell */
- extern long malloc();
-
- D5("exec(%d,\"%s\",%06lX)",cook,cmd,pp);
- r = -1;
- for (i=0; environ[i]; i++); /* How big is environ[]? */
- n = (i+5) * sizeof(char**); /* Space for copy + 5 entries */
- D5("exec: Get %d bytes for %d+5 environment entries.",n,i);
- ev = (char**)malloc(n); /* Allocate a copy for us */
- if (ev == NULL) {
- E("Can't get %d bytes for environment table [exec].",n);
- Fail;
- }
- for (e=0; environ[e]; e++) { /* Copy the environment vector */
- ev[e] = environ[e];
- D6("ev[%2d]=\"%s\"",e,ev[e]);
- }
- ev[e] = 0;
- D3("exec: There are %d environment entries.",e);
- pid = getpid();
- D4("exec: This is process %d.",pid);
- a = e = 0; /* indices for av[] and ev[] */
- for (cp=cmd; *cp; ++cp) { /* Scan the command for whitespace */
- c = *cp;
- if (c == ' ' || c == '\t') {
- av[a++] = "-sh";
- av[a++] = "-c";
- av[a++] = cmd;
- break;
- } else
- if (c == ':' || c == '\n') break;
- }
- if (a == 0) { /* the command is just a program name */
- shell = cmd; /* Note that it's our shell */
- dp = av[a++] = arg0; /* Name to tell shell */
- *dp++ = '-'; /* Build arg0 with initial '-' */
- cp = lastfield(cmd,'/'); /* Find the last field of the name */
- while (*cp) *dp++ = *cp++; /* Copy name to arg0 */
- *dp = 0; /* Gotta have a null terminator */
- D4("exec: arg0=\"%s\"",arg0);
- }
- D3("av[%2d]=\"%s\"",a-1,av[a-1]);
-
- D7("exec:before sprintf(%06lX,\"%s\",%06lX)",logn,"LOGNAME=%s\0",pp->pw_name);
- sprintf(logn,"LOGNAME=%s\0",pp->pw_name);
- D6("exec: after sprintf() logn=\"%s\"",logn);
-
- D7("exec:before sprintf(%06lX,\"%s\",%06lX)",home,"HOME=%s\0" ,pp->pw_dir);
- sprintf(home,"HOME=%s\0" ,pp->pw_dir);
- D6("exec: after sprintf() home=\"%s\"",home);
-
- D7("exec:before sprintf(%06lX,\"%s\",%06lX)",shll,"SHELL=%s\0" ,shell);
- sprintf(shll,"SHELL=%s\0" ,shell);
- D6("exec: after sprintf() shll=\"%s\"",shll);
-
- if (debug >= 5) {
- av[a++] = "-VX"; /* This turns on shell debugging */
- D3("av[%2d]=\"%s\"",a-1,av[a-1]);
- }
- av[a] = 0; /* Paranoia */
- /*
- ** This is supposed to help, but seems not to:
- **
- D4("exec: before setpgrp()");
- i = setpgrp();
- D4("exec: setpgrp()=%d",i);
- */
- lognfl = shelfl = homefl = 0; /* Flags for noticing environment entries */
- for (e=0; ev[e]; e++) { /* Examine the environment table */
- D3("exec: Examine ev[%2d]=%06lX=\"%s\"",e,ev[e],ev[e]);
- if (st_init("PATH=",ev[e]) > 0) {
- D7("exec: Matched \"PATH=\"; path=%06lX=\"%s\"",path,path);
- if (path) ev[e] = path; /* Use special path */
- D6("ev[%2d]=\"%s\"",e,ev[e]);
- pathfl++; /* Note we did it */
- }
- if (st_init("LOGNAME=",ev[e]) > 0) {
- ev[e] = logn; /* Use special path */
- D6("ev[%2d]=\"%s\"",e,ev[e]);
- lognfl++; /* Note we did it */
- }
- if (st_init("HOME=",ev[e]) > 0) {
- ev[e] = home; /* Use special path */
- D6("ev[%2d]=\"%s\"",e,ev[e]);
- homefl++; /* Note we did it */
- }
- if (st_init("SHELL=",ev[e]) > 0) {
- ev[e] = shll; /* Use special path */
- D6("ev[%2d]=\"%s\"",e,ev[e]);
- shelfl++; /* Note we did it */
- }
- }
- if (!homefl) ev[e++] = home; /* Add the home directory */
- if (!lognfl) ev[e++] = logn; /* Add the login id */
- if (!shelfl) ev[e++] = shll; /* Add the shell's name */
- if (!pathfl) ev[e++] = path; /* Add the search path (may be null) */
- D3("exec: There are %d environment entries.",e);
- ev[e] = 0; /* Paranoia */
- if (debug >= 3) { /* Display the shell's parameters */
- P("before execve(\"%s\",%lX,%lX)",shell,av,ev);
- for (i=0; av[i]; i++)
- P("arg[%2d]=\"%s\"",i,av[i]);
- for (i=0; ev[i]; i++)
- P("env[%2d]=\"%s\"",i,ev[i]);
- }
- if (debug) P("%s Start %s for u=%d=%s g=%d.",getime(),shell,pp->pw_uid,pp->pw_name,pp->pw_gid);
- if (cook) makesane(dev);
- if (dev != 0) {close(0); i = dup(dev); D3("exec: File %d=\"%s\"",i,device); }
- if (dev != 1) {close(1); i = dup(dev); D3("exec: File %d=\"%s\"",i,device); }
- child = -1; /* Default is no child process */
- pid = getpid(); /* Note which process we are now */
- if (forkfl) { /* Are we forking or execing directly? */
- D4("exec: Forking sub-process for shell.");
- if (lockfl) { /* Should we create a lockfile? */
- lockfn = creat(lockfile,0);
- if (debug >= 2)
- P("%s: Create lockfile %d=\"%s\".",getime(),lockfn,lockfile);
- if (lockfn < 0) { /* Either locked or directory isn't writable */
- E("Can't create lockfile \"%s\" [errno=%d]",lockfile,errno);
- die(errno);
- }
- locked = 1; /* Note that there's a lockfile */
- }
- if ((child = fork()) > 0) { /* Are we the parent? */
- D3("exec: %s: Shell process %d created.",getime(),child);
- if (lsleep > 0) sleep(lsleep);
- for (;;) { /* Loop until shell goes away */
- errno = 0;
- r = wait(0); /* Sleep until a subprocess dies */
- D3("%s: wait(0)=%d",getime(),r);
- if (r == child) /* Was it the shell process? */
- Done; /* If so, all's fine */
- D3("%s: After wait(0)=%d [errno=%d]",getime(),r,errno);
- if (r > 0) {
- E("%s: Wrong child %d died; waiting for %d.",getime(),r,child);
- continue;
- }
- switch(errno) {
- case ECHILD:
- D3("exec: wait(0)=%d [errno=%d=No child]",r,errno);
- Done;
- default:
- E("Unknown errno=%d after wait(0)=%d",errno,r);
- Done;
- }
- } /* Hang until the shell process dies */
- done: if (debug) sleep(1);
- D3("exec: %s: Child %d gone.",getime(),r);
- if (r > 0) r = 0;
- if (lockfl) unlock();
- if (debug) P("%s: \"%s\" done , die(%d)",getime(),shell,r);
- Fail;
- }
- }
- /*
- ** If we fall through to here, we are the process to exec a shell.
- ** We may be the original process or a subprocess.
- */
- if (debug > 1) {
- pid = getpid();
- P("%s: Shell process %d.",getime(),pid);
- }
- if (dev != 2) { close(2); i = dup(dev); }
- /**** Don't produce debug output after this! */
- errno = 0;
- if (dev>2) close(dev); /* Don't give excess open files to the shell */
- r = execve(shell,av,ev);
- E("Can't exec \"%s\"\t[errno=%d]",shell,errno);
- /*
- ** Note that we always terminate, regardless of how we get here.
- ** If we are being run from init(1), a new process will be started
- ** up. If not, we just go away. This isn't necessary, but seems
- ** in general to be a good idea.
- */
- fail: /* Both processes come here to terminate */
- if (lsleep > 0)
- sleep(lsleep); /* Don't respawn too fast */
- die(r); /* This will respawn if we're a daemon */
- }
- \!Funky\!Stuff\!
- echo file: fillutmp.c
- cat > fillutmp.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** The following routine may have to be changed for different Unices,
- ** and probably will have to be totally rewritten for other systems.
- **
- ** Fill in fields of the utmp structure *up, which may be our global
- ** utmp or may be another one returned by some library routine.
- **
- ** Here that we define our own cute copy macro, which copies <siz>
- ** bytes or to the first null, whichever comes first. Note the test
- ** to verify that the src address is nonnull.
- */
- #define CP(dst,src,siz) {p = dst; if (q = src) for (i=0; i<siz; i++) if (*q) *p++ = *q++; else *p++ = '\0';}
-
- fillutmp(name,idp,line,type)
- char *name; /* User's login id */
- char *idp; /* 4-byte line id for utmp entry */
- char *line; /* Device (port) name */
- int type;
- { char *p, *q;
- int i;
-
- D6("fillutmp(%lX,%lX,%lX,%d)",name,idp,line,type);
- if (name) D5("fillutmp: name=\"%s\"",name);
- if ( idp) D5("fillutmp: idp=\"%s\"", idp);
- if (line) D5("fillutmp: line=\"%s\"",line);
- if (up == 0) { /* No ttyslot!!! */
- D5("utmp:before setutent()");
- setutent(); /* Make pututline rescan the file */
- up = &utmp;
- }
- #ifdef SYS5
- D5("up=%06lX",up);
- D5("utmp: Copy name \"%s\"",up->ut_user);
- CP(up->ut_user,name,8); /* Fill in the user field with the login id */
- D5("utmp: Copy id \"%s\"",up->ut_id);
- CP(up->ut_id, idp, 8); /* The "id" field is from the /etc/inittab entry */
- D5("utmp: Copy line \"%s\"",up->ut_line);
- CP(up->ut_line,line,12); /* Copy the device name to the line field */
- up->ut_pid = getpid(); /* This is probably already correct, but... */
- up->ut_type = type;
- up->ut_exit.e_termination = 0; /* Default exit codes are all zero */
- up->ut_exit.e_exit = 0;
- D5("utmp: Note time...");
- time(&currtime);
- up->ut_time = currtime; /* Tell the OS when (s)he logged in */
- if (debug >= 5) Hexdnm(up,sizeof(struct utmp),"utmp");
- #endif
- /*
- ** No return value; the caller trusts us to do it right.
- */
- }
- \!Funky\!Stuff\!
- echo file: findutmp.c
- cat > findutmp.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Try to find our entry in the /etc/utmp file.
- ** If we find it, it is copied to our global utmp.
- ** This works on SYS/V, and probably on SYS/III,
- ** but likely not on anything else.
- */
- struct utmp *
- findutmp()
- { int rec; /* Record number, used in debug output */
-
- pid = getpid(); /* We are looking for an entry with out process id */
- rec = 0; /* No records read so far */
- up = 0; /* No entry unpacked so far */
- #ifdef SYS5
- setutent(); /* Restart at the top of the file */
- loop:
- D5("before getutent()");
- errno = 0;
- up = getutent(); /* Read in one /etc/utmp entry */
- ++rec;
- D4("getutent()=%06lX rec=%d\t[errno=%d]",up,rec,errno);
- if (up == 0) {
- D3("findutmp() FAILED.");
- return 0;
- }
- if (debug >= 5) Hexdnm(up,sizeof(struct utmp),"utmp");
- if (up->ut_pid != pid) {
- D4("findutmp: rec=%d pid=%d wrong.",rec,pid);
- Loop;
- }
- D4("findutmp: rec=%d pid=%d is me.",rec,pid);
- copy(&utmp,up,sizeof(struct utmp));
- up = &utmp;
- return up;
- #endif
- }
- \!Funky\!Stuff\!
- echo file: gestate.c
- cat > gestate.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Look up the current state and return its symbolic name.
- **
- ** The state[] array is the list of known states. Note that
- ** we assume that states are non-negative, and use -1 as an
- ** end-of-array flag. Note also that zero is a highly-likely
- ** state, and should be included as a distinct state (probably
- ** S_INIT). The order is irrelevant, except for speed; a linear
- ** lookup is done.
- */
- struct state {int ssval; char *ssnam; } state[] = {
- {S_EXIT, "EXIT"},
- {S_IDLE, "IDLE"},
- {S_INIT, "INIT"},
- {S_LOGIN, "LOGIN"},
- {S_PASSWD, "PASSWD"},
- {-1, "UNKNOWN"}
- };
- char *
- gestate()
- { int i;
-
- for (i=0; state[i].ssval >= 0; i++)
- if (state[i].ssval == ss)
- return state[i].ssnam;
- return state[i].ssnam; /* Final "unknown" state */
- }
- \!Funky\!Stuff\!
- echo file: getime.c
- cat > getime.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** Get the current local time, return pointer to the ASCII version.
- */
- char *getime()
- {
- time(&currtime); /* 32-bit UNIX timestamp */
- ctimep = ctime(&currtime); /* Convert to ASCII */
- ctimep[24] = '\0'; /* We don't want the newline */
- return ctimep;
- }
- \!Funky\!Stuff\!
- echo file: help.c
- cat > help.c << '\!Funky\!Stuff\!'
- #include "uutty.h"
- /*
- ** The -h option triggers this routine. We should try to
- ** keep it up to date, so users can find out easily what
- ** options are currently supported.
- */
- help()
- {
- P("usage: %s [-options] [device] [2>auditfile]",progname);
- P("options are:");
- P("\t-b<n>\tSet baud rate to <n>.");
- P("\t-c<n>\tCount to <n> before reads.");
- P("\t-e<msg>\tMessage to send to port before exiting.");
- P("\t-f\tFork (create subprocess) to start shells.");
- P("\t-h\tHelp--display this information.");
- P("\t-i<msg>\tMessage to send for initalizing port.");
- P("\t-l\tCreate uucp lockfiles for successful logins.");
- P("\t-n<msg>\tMessage to send to nudge the port.");
- P("\t-p<f>\tPort name is <f>.");
- P("\t-r<n>\tRaw I/O [default=1=true].");
- P("\t-s<n>\tSleep <n> seconds before reads.");
- P("\t-x<n>\tDebug level of <n>.");
- P("Note that error output [file 2] is used for debugging.");
- }
- \!Funky\!Stuff\!
-
-
-